﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Extensil.Common.CategoryHandler.Discovery;
using System.IO;
using System.Net;
using System.Globalization;
using System.Xml;
using System.Xml.Linq;

namespace Extensil.Discovery.SPDL
{
    public class SPDiscovery : BaseProbeHandler
    {
        CategoryList.Lists _listService;
        ProbeParamList _paramList;
        public override string[] Keys
        {
            get
            {
                return new string[] { "SiteUrl", "DocumentLibrary" };
            }
        }
        public override bool ValidateParam(ProbeParamList paramList)
        {
            if(!paramList.ContainsName("SiteUrl"))
                throw new Exception("Parameter SiteUrl is required to establish connection with Sharepoint.");
            else if(String.IsNullOrEmpty(paramList["SiteUrl"].Trim()))
                throw new Exception("SiteUrl must be a valid sharepoint link.");

            if(!paramList.ContainsName("DocumentLibrary"))
                throw new Exception("Parameter DocumentLibrary is required to establish connection with Sharepoint.");
            else if(String.IsNullOrEmpty(paramList["DocumentLibrary"].Trim()))
                throw new Exception("DocumentLibrary must be a valid sharepoint document library.");

            return true;
        }
        public override void Connect(ProbeParamList paramList)
        {
            try
            {
                _paramList = paramList;
                _listService = new Extensil.Discovery.SPDL.CategoryList.Lists();
                _listService.Url = paramList["SiteUrl"] + "/_vti_bin/Lists.asmx";
                _listService.Credentials = System.Net.CredentialCache.DefaultCredentials;
                ReportStatus("Connected to Sharepoint");
            }
            catch(FileNotFoundException exc)
            {
                throw new Exception("You are not authorized.");
            }
        }
        public override DiscoveryResultList Search()
        {
            ReportStatus("Searching for updates.");
            XmlDocument xmlDoc = new System.Xml.XmlDocument();
            XmlNode ndQuery = xmlDoc.CreateNode(XmlNodeType.Element, "Query", "");
            XmlNode ndViewFields = xmlDoc.CreateNode(XmlNodeType.Element, "ViewFields", "");
            XmlNode ndQueryOptions = xmlDoc.CreateNode(XmlNodeType.Element, "QueryOptions", "");

            ndQueryOptions.InnerXml = "<IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns>" +
                "<DateInUtc>TRUE</DateInUtc>";
            ndViewFields.InnerXml = "<FieldRef Name='Title' /><FieldRef Name='PluginVersion'/><FieldRef Name='Modified'/><FieldRef Name='EncodedAbsUrl'/><FieldRef Name='Description0'/><FieldRef Name='AutoUpdate'/>";
            try
            {
                XmlNode ndListItems = _listService.GetListItems(_paramList["DocumentLibrary"], null, ndQuery, 
                    ndViewFields, null, ndQueryOptions, null);

                var xData = XElement.Parse(ndListItems.InnerXml);
                var results = (from x in xData.DescendantsAndSelf(XName.Get("row", "#RowsetSchema"))
                                 select new DiscoveryResult
                                 {
                                     Name = x.Attribute("ows_Title").Value,
                                     Description = x.Attribute("ows_Description0").Value,
                                     Link = x.Attribute("ows_EncodedAbsUrl").Value,
                                     AutoUpdate = (bool)x.Attribute("ows_AutoUpdate"),
                                     ModifiedOn = ((DateTime)x.Attribute("ows_Modified")).ToLocalTime(), 
                                     Version = new Version(x.Attribute("ows_PluginVersion").Value)
                                 });
                if(results != null)
                {
                    return DiscoveryResultList.Convert(results.ToList());
                }
            }

            catch(System.Web.Services.Protocols.SoapException ex)
            {
                ReportStatus(ex.Message + "\nDetail:\n" + ex.Detail.InnerText);
            }
            catch(Exception ex)
            {
                ReportStatus(ex.Message);
            }
            return new DiscoveryResultList();
        }
        public override DiscoveryResultList Search(DateTime modifiedOrAddedSince)
        {
            return new DiscoveryResultList();
        }
        public override string DownloadPlugin(string path)
        {
            Uri url = new Uri(path);
            WebRequest request = WebRequest.Create(url);
            request.UseDefaultCredentials = true;
            WebResponse response = request.GetResponse();
            Stream fs = response.GetResponseStream() as Stream;

            string fileName = url.Segments[url.Segments.Length - 1];
            using(FileStream localfs = File.OpenWrite(fileName))
            {
                CopyStream(fs, localfs);
            }
            return fileName;
        }
        void CopyStream(Stream input, Stream output)
        {
            byte[] buffer = new byte[8 * 1024];
            int len;
            while((len = input.Read(buffer, 0, buffer.Length)) > 0)
            {
                output.Write(buffer, 0, len);
            }
        }
    }
}
